#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
#include <iostream>
#include <mutex>

#include "logger.hpp"

namespace im{

typedef websocketpp::server<websocketpp::config::asio> server;

    class Connection{
        public:
            using ptr = std::shared_ptr<Connection>;
            struct Client{
                std::string user_id;
                std::string session_id;
            };
        
        Connection(){}

        /// @brief 根据user_id来建立长连接
        /// @param conn websocket长连接
        /// @param user_id 用户id
        /// @param session_id 登入会话id，由用户注册时用户子服务生成
        /// @return void
        void insert(const server::connection_ptr& conn, const std::string& user_id, const std::string& session_id){
            std::unique_lock<std::mutex> lock(_mutex);
            _uid_connections.insert(std::make_pair(user_id, conn));
            _conn_clients.insert(std::make_pair(conn, Client{user_id, session_id}));
            LOG_DEBUG("用户ID： {} 新建长连接",user_id);
        }

        /// @brief 根据user_id来获取长连接
        /// @param user_id 用户id
        /// @return connection_ptr websocket长连接
        server::connection_ptr connection(const std::string& user_id){
            std::unique_lock<std::mutex> lock(_mutex);
            if(_uid_connections.find(user_id) != _uid_connections.end()){
                return _uid_connections[user_id];
            }
            return nullptr;
        }

        /// @brief 根据websocket长连接来获取用户信息
        /// @param conn websocket长连接
        /// @param user_id 输出型参数 用户id
        /// @param session_id 输出型参数 登入会话id
        /// @return bool 是否成功
        bool client(const server::connection_ptr& conn, std::string& user_id, std::string& session_id){
            std::unique_lock<std::mutex> lock(_mutex);
            if(_conn_clients.find(conn) != _conn_clients.end()){
                user_id = _conn_clients[conn].user_id;
                session_id = _conn_clients[conn].session_id;
                return true;
            }
            return false;
        }

        /// @brief 根据connection_ptr来删除长连接
        /// @param conn websocket长连接
        void remove(const server::connection_ptr &conn){
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _conn_clients.find(conn);
            if(it == _conn_clients.end()){
                LOG_CRITICAL("有链接{}，但无用户消息", (size_t)conn.get());
                return;
            }
            _uid_connections.erase(it->second.user_id);
            _conn_clients.erase(it);
        }

        /// @brief 根据user_id来删除长连接
        /// @param user_id 用户id
        void remove(std::string& user_id){
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _uid_connections.find(user_id);
            if(it == _uid_connections.end()){
                LOG_CRITICAL("用户ID:{}，但无链接消息",user_id);
                return;
            }
            _conn_clients.erase(it->second);
            _uid_connections.erase(it);
        }

        private:
            std::mutex _mutex;
            std::unordered_map<std::string, server::connection_ptr> _uid_connections;
            std::unordered_map<server::connection_ptr, Client> _conn_clients;
    };
}